<?php
declare(strict_types=1);
namespace App\Game\Server;

use App\Service\ChatService;
use App\Service\RoomService;
use App\Service\UserService;
use Closure;
use Hyperf\Contract\StdoutLoggerInterface;
use Swoole\WebSocket\Server;
use Hyperf\Di\Annotation\Inject;

/**
 * 大厅服务逻辑处理
 * Class HallServer
 * @package App\Game
 */

class HallServer
{
    /**
     * 依赖注入 日志服务
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $console;

    /**
     * 登录
     * @param Closure $next
     * @param Server $server
     * @param array $params
     * @return mixed
     */
    public function login(Closure $next, Server $server, array $params)
    {
        //验证参数
        $username = $params['username'] ?? '';
        $password = $params['password'] ?? '';
        if (!$username || !$password) {
            dump($params);
            return $next(error('参数错误！'));
        }
        //验证账号
        $user = UserService::getUserByUsername($username);
        if (!$user) {
            return $next(error('用户名不存在！'));
        }
        //验证密码
        if (sha1($password) !== $user['password']) {
            return $next(error('密码错误！'));
        }
        //断开之前账号。
        $last_user = UserService::getUserRedis($user['uid']);
        if ($last_user) {
            $server->close((int)$last_user['fd']);
        }
        //绑定uid
        $server->bind($params['fd'], $user['uid']);

        //初始化用户数据
        $user = $user->toArray();
        $user['fd'] = $params['fd'];
        UserService::initGameUser($user);
        $this->console->info("$user[username] $user[uid] 登录成功");
        return $next(success());
    }

    /**
     * 退出登录
     * @param Server $server
     * @param int $fd
     */
    public function logout(Server $server, int $fd)
    {
        $user = UserService::getUserByFd($fd, $server);
        //清除数据
        if ($user && $user['fd'] == $fd) {
            //用户房间踢出
            RoomService::kickUser($user);
            UserService::removeUserRedis($user['uid']);
            $this->console->info("用户 $user[uid] 信息已清除");
        }
    }

    /**
     * 创建房间
     * @param Closure $next
     * @param Server $server
     * @param array $params
     * @return mixed
     */
    public function createRoom(Closure $next, Server $server, array $params)
    {
        //验证状态
        $user = UserService::getUserByFd($params['fd'], $server);
        if (!$user) {
            return $next(error('请先登录'));
        }

        //验证数据
        if (!isset($params['room_name']) || empty($params['room_name'])) {
            return $next(error('房间名称错误'));
        }

        //判断是否已经在房间中
        if (isset($user['room_id']) && !empty($user['room_id'])) {
            return $next(error('你已经在房间中'));
        }
        //房间号
        $room_id = RoomService::getRoomId() + 1;
        //更新房间编号
        RoomService::updateRoomId($room_id);
        //房主添加至房间中
        RoomService::addUserToRoom($user['uid'], $room_id);
        //存储房间信息
        RoomService::updateRoom($room_id, ['room_id' => $room_id, 'room_name' => $params['room_name'], 'owner' => $user['uid'], 'max_user' => 4, 'count' => 1, 'table1' => $user['uid']]);
        //添加编号至系统中
        RoomService::addRoomID($room_id);
        //更新用户信息房间编号
        UserService::updateUserRedis($user['uid'], ['room_id' => $room_id, 'table' => 1]);

        $this->console->info("$user[uid] 创建房间 $room_id");
        return $next(success(['room_id' => $room_id]));
    }

    /**
     * 加入房间
     * @param Closure $next
     * @param Server $server
     * @param array $params
     * @return mixed
     */
    public function intoRoom(Closure $next, Server $server, array $params)
    {
        //验证状态
        $user = UserService::getUserByFd($params['fd'], $server);
        if (!$user) {
            return $next(error('请先登录'));
        }

        //验证参数
        $room_id = @(int)$params['room_id'];
        if (!$room_id) {
            return $next(error('房间编号错误'));
        }
        //判断是否已经在房间中
        if (isset($user['room_id']) && !empty($user['room_id'])) {
            return $next(error('你已经在房间中'));
        }
        //检查房间
        $room = RoomService::getRoom($room_id);
        if (!$room) {
            return $next(error('房间不存在'));
        }
        //判断人数
        if ($room['count'] >= 4) {
            return $next(error('房间人数已满'));
        }
        //加入房间
        RoomService::addUserToRoom($user['uid'], $room_id);
        //更新用户信息
        $table = RoomService::getEnableTable($room);
        UserService::updateUserRedis($user['uid'], ['room_id' => $room_id, 'table' => $table]);
        //更新房间信息
        RoomService::updateRoom($room_id, ['count' => $room['count'] + 1, 'table'.$table => $user['uid']]);
        //加入房间通知
        ChatService::msgToRoom("$user[username] 加入房间", $room_id, $server, 0);
        $this->console->info("$user[uid] 加入房间 $room_id, 桌子: $table");
        return $next(success());
    }


    /**
     * 更换座位
     * @param Closure $next
     * @param Server $server
     * @param array $params
     */
    public function changeRoomTable(Closure $next, Server $server, array $params)
    {
        //验证状态
        $user = UserService::getUserByFd($params['fd'], $server);
        if (!$user) {
            return $next(error('请先登录'));
        }
        //验证参数
        $table = $params['table'] ?? 0;
        if (!$table || !in_array($table, [1, 2, 3, 4])) {
            return $next(error('参数错误'));
        }
        //检测桌子
        if (!isset($user['table']) || !$user['table']) {
            return $next(error('当前不在桌子上'));
        }
        $room = RoomService::getRoom($user['room_id']);
        if (!$room) {
            return $next(error('房间不存在'));
        }
        $sit = 'table'.$table;
        if (isset($room[$sit]) && $room[$sit]) {
            return $next(error('该桌子上已经有人了'));
        }
        //换座
        RoomService::updateRoom($room['room_id'], [$sit => $user['uid'], 'table'.$user['table'] => 0]);
        //更新用户信息
        UserService::updateUserRedis($user['uid'], ['table' => $table]);
        $this->console->info("房间 $room[room_id] $user[uid] 由 $user[table] 换到了 $table");
        return $next(success());
    }

    /**
     * 发送消息
     * @param Closure $next
     * @param Server $server
     * @param array $params
     * @return mixed
     */
    public function chat(Closure $next, Server $server, array $params)
    {
        //验证状态
        $user = UserService::getUserByFd($params['fd'], $server);
        if (!$user) {
            return $next(error('请先登录'));
        }

        $msg = $params['msg'] ?? '';
        $type = $params['type'] ?? 0;   //1私聊 2房间

        if (!$msg || !in_array($type, [1, 2])) {
            return $next(error('参数错误！'));
        }
        if ($type == 1) {
            //私聊
            $to = $params['to'] ?? 0;
            if (!$to) {
                return $next(error('参数错误！'));
            }
            $f = UserService::getUserRedis($to);
            if (!$f) {
                return $next(error('未找到该用户'));
            }
            ChatService::msg($msg, $f['fd'], $server, $user['uid'], $type);
        } else if ($type == 2) {
            //房间
            $room_id = $user['room_id'] ?? 0;
            if (!$room_id) {
                return $next(error('当前不在房间'));
            }
            ChatService::msgToRoom($msg, $room_id, $server, $user['uid']);
        }
        return $next(success());
    }

    /**
     * 准备
     * @param Closure $next
     * @param Server $server
     * @param array $params
     * @return mixed
     */
    public function ready(Closure $next, Server $server, array $params)
    {
        //验证状态
        $user = UserService::getUserByFd($params['fd'], $server);
        if (!$user) {
            return $next(error('请先登录'));
        }
        //检测桌子
        if (!isset($user['table']) || !$user['table']) {
            return $next(error('当前不在桌子上'));
        }
        if (isset($user['is_ready']) && $user['is_ready'] > 0) {
            return $next(error('你已经准备过了'));
        }
        UserService::updateUserRedis($user['uid'], ['is_ready' => 1]);
        RoomService::updateRoom($user['room_id'], ['table'.$user['table'].'_ready' => 1]);
        return $next(success());
    }

    /**
     * 检查客户端是否正常 检测心跳
     */
    public function checkConnect()
    {
        $this->console->info('正在检测客户端是否正常！');
        $websocket = websocket();
        if (isset($websocket->connections)) {
            foreach ($websocket->connections as $fd) {
                $info = $websocket->getClientInfo($fd);
                //5秒未内未收到消息则断开
                if ($websocket->exist($fd) && $info['websocket_status'] > 0 && $info['last_send_time'] < time() - 5)  {
                    $this->console->info("客户端 $fd 超时");
                    $websocket->close($fd);
                }
            }
        }
    }
}